/*************************************************************/
/*                                                           */
/*     MC823 - Laboratorio de Teleprocessamento e Redes      */
/*     1 Semestre / 2013                                     */
/*     Projeto 1 - Cliente e Servidor TCP/UDP de uma Livraria*/
/*                                                           */
/*     Alunos: Joao Gabriel M.D.Mendes - RA 102788           */
/*             Lucas Domingues Lima    - RA 103140           */
/*                                                           */
/*************************************************************/

/* Arquivo: /servidor/livraria.c
	Definicao: Funcoes para criar camada de persistencia e atender as
              solicitacoes feitas pela servidor.
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "livraria.h" 


// -------- FUNCOES DE CRIACAO DA CAMADA DE PERSISTENCIA ------------

/* Funcao responsavel por alocar a memoria dinamicamente e preencher com 
   as informaçcoes dos livros.
*/
t_estoque* criaEstoque()
{

    // Cria tipo estoque
    t_estoque *novoestoque = (t_estoque*) malloc(sizeof(t_estoque));
    t_livro *prox_livro;
    char** estoqueinicial;
    int tamanho, aux = 0;

    /* A funcao carregaEstoqueInicial retorna um vetor com os campos de
       inforcacao dos livros do estoque */
    estoqueinicial = carregaEstoqueInicial();
    
    tamanho = atoi(estoqueinicial[0]);

    // Aloca o primeiro livro e seu conteudo.
    novoestoque->livros = (t_livro*) malloc(sizeof(t_livro));
    
    prox_livro = novoestoque->livros;
   
    prox_livro->isbn = estoqueinicial[aux+1];
    prox_livro->titulo = estoqueinicial[aux+2];
    prox_livro->autor = estoqueinicial[aux+3];
    prox_livro->descricao = estoqueinicial[aux+4];
    prox_livro->editora = estoqueinicial[aux+5];
    prox_livro->ano = estoqueinicial[aux+6];
    prox_livro->num = atoi(estoqueinicial[aux+7]);
    
    aux = aux + 7;

    // Aloca os outros livros no estoque
   
    while(aux < tamanho-7) {

      prox_livro->proximo = (t_livro*) malloc(sizeof(t_livro));

      prox_livro = prox_livro->proximo;

      prox_livro->isbn = estoqueinicial[aux+1];
      prox_livro->titulo = estoqueinicial[aux+2];
      prox_livro->autor = estoqueinicial[aux+3];
      prox_livro->descricao = estoqueinicial[aux+4];
      prox_livro->editora = estoqueinicial[aux+5];
      prox_livro->ano = estoqueinicial[aux+6];
      prox_livro->num = atoi(estoqueinicial[aux+7]);
      
      aux = aux + 7;
    
    }
    
    prox_livro->proximo = NULL;

    // Retorna o estoque

    return novoestoque;
}

// -------- FUNCOES DE LIBERACAO DA CAMADA DE PERSISTENCIA ------------

/* Funcao responsavel por liberar a memoria alocada para um livro */
void liberaLivro(t_livro *temp)
{
    free(temp->titulo);
    free(temp->autor);
    free(temp->descricao);
    free(temp->editora);
    free(temp->ano);
    free(temp->isbn);
    free(temp);
    return;
}

/* Funcao responsavel por liberar a memoria de todos os livros do estoque */
void liberaLivros(t_livro *livro)
{
    if(livro == NULL)
        return;

    liberaLivros(livro->proximo);
    liberaLivro(livro);
    return;
}

/* Funcao responsavel por liberar a memoria do estoque */
void liberaEstoque(t_estoque *estoque)
{
    liberaLivros(estoque->livros);
    free(estoque);
    return;
}

// -------- FUNCOES AUXILIARES ------------

/* Funcao que concatena dois trechos de texto com um separador entre eles */
char* ConcatenaEspecial(char *a,char *b,char sep)
{
    int tamA,tamB,i,j;
    char *temp;

    // Testes caso um ou os dois dos trechos sejam NULL
    if(a == NULL && b == NULL)
        return NULL;
    if(a == NULL)
        return strdup(b);
    if(b == NULL)
        return strdup(a);

    // Obtem os tamanhos das strings e concatena
    tamA = strlen(a);
    tamB = strlen(b);
    temp = (char*) malloc(sizeof(char)*(tamA+tamB+2));

    for(i=0;i<tamA;i++)
        temp[i] = a[i];
    temp[i] = sep;

    j = 0;
    for(i=tamA+1;i<tamA+1+tamB;i++)
        temp[i] = b[j++];
    temp[i] = '\0';


    // Retorna a string concatenada
    return temp;
}

/* Funcao que le o arquivo base do estoque e retorna o numero de
   linhas que ele possui. 
*/
int retornaTamArquivo(FILE *arq)
{
    int i;
    char c;

    /* Le a primeira linha e faz o loop pelas quebras de linha ate o fim do 
       arquivo */
    i=0;
    fscanf(arq,"%c",&c);
    while(!feof(arq))
    {
        if(c == '\n')
            i++;
        fscanf(arq,"%c",&c);
    }

    fseek(arq,0,SEEK_SET);

    // Retorna o numero de linhas
    return i+1;
}

/* Funcao que le o arquivo base e transforma ele em um vetor de strings para
   inicializacao do estoque
*/
char** carregaEstoqueInicial()
{
    int i,j;
    int tam;
    FILE *arq;
    char c,buf[100],**base;
    char aux[10];

    // Abre o arquivo e obtem o seu tamanho
    arq = fopen("../estoqueinicial.txt","r");
    tam = retornaTamArquivo(arq);

    // Aloca o vetor de strings e faz o loop até o fim do arquivo copiando
    // suas linhas. Usa um buffer para ler todos os caracteres de uma linha
    // antes de alocar no vetor.
    base = (char**) malloc(sizeof(char*)*(tam));
   
    j=1;
    while(!feof(arq))
    {
        i=0;
        fscanf(arq,"%c",&c);
        while(c != '\n' && !feof(arq))
        {
            buf[i++] = c;
            fscanf(arq,"%c",&c);
        }
        if(!feof(arq))
        {
            buf[i] = '\0';
            base[j] = strdup(buf);
            j++;
        }
    }
    
    // Coloca na primeira posicao do vetor o numero de linhas e retorna
    sprintf(aux,"%d",j);
    base[0] = strdup(aux);

    return base;
}

// -------- FUNCOES PRINCIPAIS QUE EXECUTAM AS REQUISICOES ------------

/* Funcao que atende a solicitacao A, de retornar o titulo dos livros no
   estoque e seus ISBNs.
*/
char* retornaTitulosISBN(t_estoque *estoque)
{

  char* mensagem = NULL;
  char *aux1, *aux2;
  t_livro* livro = estoque->livros;

  // Se estoque vazio, avisa.
  if(estoque == NULL) {
    mensagem = strdup("Estoque vazio.");
    return mensagem;
  }
  
  // Passa pelo vetor de livros, obtem o isbn do livro e seu titulo, e aloca
  // em uma mensagem de retorno. 
  while(livro != NULL) {
    aux1 = mensagem;
    aux2 = ConcatenaEspecial(aux1, livro->isbn, '\n');
    mensagem = ConcatenaEspecial(aux2, livro->titulo, '|');
    livro = livro->proximo;
  }
  
  return mensagem;

}

/* Funcao que atende a solicitacao B, de retornar todas as informacoes dos
   livros no estoque.
*/
char* retornaInfoEstoque(t_estoque *estoque)
{
  
  char* mensagem = NULL;
  char *aux1, *aux2, *numero;
  char num[10];
  t_livro* livro = estoque->livros;

  // Se estoque vazio, avisa.
  if(estoque == NULL) {
    mensagem = strdup("Estoque vazio.");
    return mensagem;
  }


  // Passa pelo vetor de livros, obtem as informacoes dos livros, e aloca
  // em uma mensagem de retorno.   
  while(livro != NULL) {
  
    sprintf(num,"%d",livro->num);
    numero = strdup(num);
  
    aux1 = mensagem;
    aux2 = ConcatenaEspecial(aux1, livro->isbn, '\n');
    aux1 = ConcatenaEspecial(aux2, livro->titulo, '|');
    aux2 = ConcatenaEspecial(aux1, livro->autor, '|');
    aux1 = ConcatenaEspecial(aux2, livro->descricao, '|');
    aux2 = ConcatenaEspecial(aux1, livro->editora, '|');
    aux1 = ConcatenaEspecial(aux2, livro->ano, '|');
    mensagem = ConcatenaEspecial(aux1, numero, '|');

    livro = livro->proximo;
    
  }
  
  return mensagem;
}

/* Funcao que atende a solicitacao C, de retornar a descricao de um livro
   especifico no estoque, dado o seu isbn.
*/
char* retornaDescricao(t_estoque *estoque, char *isbn)
{
 
  char* mensagem = NULL;
  t_livro* livro = estoque->livros;

  // Se estoque vazio, avisa.
  if(estoque == NULL) {
    mensagem = strdup("Estoque vazio.");
    return mensagem;
  }
  
  // Percorre o vetor de livros procurando pelo livro por seu isbn
  while(livro != NULL) {
    if(!strcmp(livro->isbn,isbn)) {
      return livro->descricao;
    }
    livro = livro->proximo;
  }
  
  // Caso o livro nao seja encontrado, avisa.
  mensagem = strdup("Livro nao encontrado.");
    
  return mensagem;
 
}

/* Funcao que atende a solicitacao D, de retornar todas as informacoes de 
   um livro dado o seu isbn.
*/
char* retornaInfoLivro(t_estoque *estoque, char *isbn)
{

  char* mensagem = NULL;
  char *aux1, *aux2, *numero;
  char num[10];
  t_livro* livro = estoque->livros;

  // Se estoque vazio, avisa.
  if(estoque == NULL) {
    mensagem = strdup("Estoque vazio.");
    return mensagem;
  }
  
  // Percorre o vetor de livros procurando pelo livro por seu isbn
  while(livro != NULL) {
    if(!strcmp(livro->isbn,isbn)) {

      sprintf(num,"%d",livro->num);
      numero = strdup(num);
  
      aux1 = ConcatenaEspecial(livro->isbn, livro->titulo, '|');
      aux2 = ConcatenaEspecial(aux1, livro->autor, '|');
      aux1 = ConcatenaEspecial(aux2, livro->descricao, '|');
      aux2 = ConcatenaEspecial(aux1, livro->editora, '|');
      aux1 = ConcatenaEspecial(aux2, livro->ano, '|');
      mensagem = ConcatenaEspecial(aux1, numero, '|');
      
      return mensagem;
    }
    livro = livro->proximo;
  }

  // Caso o livro nao seja encontrado, avisa.  
  mensagem = strdup("Livro nao encontrado.");
  
  return mensagem;

}

/* Funcao que atende a solicitacao E, de retornar o numero em estoque
    de um dado livro, com base em seu isbn.
*/
char* retornaNumLivro(t_estoque *estoque, char *isbn)
{

  char* mensagem = NULL;
  char* numero;
  char num[10];
  t_livro* livro = estoque->livros;

  // Se estoque vazio, avisa.
  if(estoque == NULL) {
    mensagem = strdup("Estoque vazio.");
    return mensagem;
  }

  // Percorre o vetor de livros procurando pelo livro por seu isbn
  while(livro != NULL) {
    if(!strcmp(livro->isbn,isbn)) {
      sprintf(num,"%d",livro->num);
      numero = strdup(num);   
      return numero;
    }
    livro = livro->proximo;
  }

  // Caso o livro nao seja encontrado, avisa.  
  mensagem = strdup("Livro nao encontrado.");
    
  return mensagem;

}

/* Funcao que atende a solicitacao F, de alterar o numero de um determinado
	livro em estoque.
*/
char* alteraEstoque(t_estoque *estoque, char *isbn, int num)
{

  char* mensagem = NULL;
  t_livro* livro = estoque->livros;

  // Se estoque vazio, avisa.
  if(estoque == NULL) {
    mensagem = strdup("Estoque vazio.");
    return mensagem;
  }

  // Percorre o vetor de livros procurando pelo livro por seu isbn, ao
  // encontrar altera seu valor
  while(livro != NULL) {
    if(!strcmp(livro->isbn,isbn)) {
      livro->num = num;
      mensagem = strdup("Estoque atualizado com sucesso.");
      return mensagem;
    }
    livro = livro->proximo;
  }
 
  // Caso o livro nao seja encontrado, avisa. 
  mensagem = strdup("Livro nao encontrado.");
    
  return mensagem;

}
